package com.wanxi.spring.cloud.zuul.service.impl;

import com.wanxi.spring.cloud.commons.api.CommonResult;
import com.wanxi.spring.cloud.zuul.jwt.JwtTokenUtil;
import com.wanxi.spring.cloud.zuul.mapper.UserMapper;
import com.wanxi.spring.cloud.zuul.model.Permission;
import com.wanxi.spring.cloud.zuul.model.User;
import com.wanxi.spring.cloud.zuul.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 蒋帆
 * @since 2020-12-21
 */
@Service("userDetailsService")
@CacheConfig(cacheNames = "springcloud::user")
public class UserServiceImpl implements UserService, UserDetailsService {

    private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
    @Autowired
    JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.tokenHead}")
    private String tokenHead;//bearer

    @Value("${jwt.tokenHeader}")//Authorization
    private String tokenHeader;

    @Autowired(required = false)
    UserMapper userMapper;
    @Autowired
    RedisServiceImpl redisService;

    @Override
    public CommonResult getUserByName(String username) {//根据用户名获取用户
        User user = null;//判断缓存是否有该用户
        if (!redisService.hasKey("springcloud::user::" + username))
            user = userMapper.getUserByName(username);//如果没有，访问数据库
        else//如果有，则直接从缓存中拿到该值
            user = (User) redisService.get("springcloud::user::" + username);
        return CommonResult.success(user);
    }

    @Override
    public CommonResult sendToken(HttpServletRequest request) {
        //从 header  中获取 Authorization
        String authHeader = request.getHeader(this.tokenHeader);
        // 判断 authHeader  不为空  并且以 bearer 开头
        if (authHeader != null) {
            boolean b1 = org.springframework.util.StringUtils.startsWithIgnoreCase(authHeader, this.tokenHead);
            if (b1) {
                //截取 bearer 后面的字符串  并且 两端去空格（获取token）
                String authToken = authHeader.substring(this.tokenHead.length()).trim();// The part after "Bearer "

                String username = jwtTokenUtil.getUserNameFromToken(authToken);
                if (username == null) {
                    return CommonResult.failed("token已失效");
                } else {
                    LOGGER.info("checking username:{}", username);
                    //验证权限
                    //从数据库读取用户信息
                    UserDetails userDetails = loadUserByUsername(username);
                    //校验token
                    if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        WebAuthenticationDetails details = new WebAuthenticationDetailsSource().buildDetails(request);
                        //设置用户ip
                        authentication.setDetails(details);
                        LOGGER.info("authenticated user:{}", username);
                        boolean b = SecurityContextHolder.getContext().getAuthentication() == null;
                        if (b) {
                            //存入本线程的安全容器   在访问接口拿到返回值后 要去主动清除权限，避免干扰其他的线程
                            SecurityContextHolder.getContext().setAuthentication(authentication);
                        }
                        return CommonResult.success(userDetails);
                    } else
                        return CommonResult.failed("token验证失败");
                }
            } else
                return CommonResult.validateFailed("token无效");
        } else {
            return CommonResult.forbidden("无token");
        }
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user= userMapper.getUserByName(username);
        List<Permission> permissionList= userMapper.getPermissionsByUserId(user.getId());
        HashSet<Permission> permissions = new HashSet<>(permissionList);
        user.setAuthorities(permissions);
        return user;
    }
}
